#ifndef ELFPARSER_H
#define ELFPARSER_H

#include <Globals.h>

#define SHT_PROGBITS      0x1     // The data is contained in the program file.
#define SHT_SYMTAB	      0x2	  // Symbol table
#define SHT_STRTAB	      0x3	  // String table
#define SHT_RELA          0x4
#define SHT_HASH          0x5     // Symbol hash table
#define SHT_DYNAMIC       0x6     // Dynamic linking information
#define SHT_NOTE          0x7
#define SHT_NOBITS        0x8     // The data is not contained in the program file.
#define SHT_REL           0x9
#define SHT_DYNSYM        0xb
#define SHT_INIT_ARRAY    0xe
#define SHT_FINI_ARRAY    0xf
#define SHT_PREINIT_ARRAY 0x10

#define SHF_WRITE         0x1
#define SHF_ALLOC         0x2
#define SHF_EXECINSTR     0x4
#define SHF_MASKPROC      0xf0000000

#define ELF32_R_SYM(val)  ((val) >> 8)
#define ELF32_R_TYPE(val) ((val) & 0xff)

typedef struct
{
  u8int  ident[16];
  u16int type;
  u16int machine;
  u32int version;
  u32int entry;
  u32int phoff;
  u32int shoff;
  u32int flags;
  u16int ehsize;
  u16int phentsize;
  u16int phnum;
  u16int shentsize;
  u16int shnum;
  u16int shstrndx;
} Elf32Header;

typedef struct
{
  u32int type;
  u32int offset;
  u32int vaddr;
  u32int paddr;
  u32int filesz;
  u32int memsz;
  u32int flags;
  u32int align;
} Elf32ProcessHeader;

typedef struct
{
  u32int name;
  u32int type;
  u32int flags;
  u32int addr;
  u32int offset;
  u32int size;
  u32int link;
  u32int info;
  u32int addralign;
  u32int entsize;
} Elf32SectionHeader;

typedef struct
{
  u32int name;
  u32int value;
  u32int size;
  u8int  info;
  u8int  other;
  u16int shndx;
} Elf32Symbol;

typedef struct
{
  s32int tag;
  union
  {
    s32int val;
    u32int ptr;
  } un;
} Elf32Dyn;

typedef struct
{
  u32int offset;
  u32int info;
} Elf32Rel;

/**
  Parses an ELF file, generating symbolic information and loading code/data segments.
**/
class Elf32Parser
{

public:
  /**
    Creates a blank ELF parser, preparing for a call to loadKernel.
  **/
  Elf32Parser();

  /**
    Creates the ELF parser based on a file.
  **/
  Elf32Parser(char *fname);
  
  ~Elf32Parser();
  
  /**
    Duplicates (this), performing a deep copy.
  **/
  Elf32Parser *clone();

  /**
    Writes all section information to the virtual memory image.
  **/
  void writeAllSections();
  
  /**
    Returns the address of the last byte to be loaded in.
  **/
  Address getLastAddress();
  
  /**
    Loads the symbol table for the kernel from the specified location.
  **/
  void loadKernel(Elf32SectionHeader *symtab, Elf32SectionHeader *strtab);
  
  /**
    Returns the symbol name for an address. Also returns the start address
    of that symbol in startAddr if startAddr != NULL.
  **/
  char *findSymbol(Address addr, Address *symbolStart=NULL);

  /**
    Returns the address of a symbol with name str.
    NOTE: This is much slower than it should be. This should be implemented
    using the hashtable sections in ELF.
  **/
  Address findSymbol(char *str);
  
  /**
    Returns the address of the symbol with offset o in the
    relocation symbol table.
  **/
  Address findDynamicSymbolLocation(Address o);
  
  /**
    Returns a NULL terminated string specifying the name of 
    the symbol at offset o in the relocation symbol table.
  **/
  char *findDynamicSymbolName(Address o);
  
  /**
    Gets the address of the global offset table.
  **/
  Address getGlobalOffsetTable();
  
  /**
    Returns the entry point of the executable.
  **/
  Address getEntryPoint()
  {
    return (Address)header->entry;
  }
  
  /**
    Returns true if the parser loaded correctly.
  **/
  bool isValid()
  {
    return (filename!=0);
  }
  
private:
  Elf32Header        *header;
  Elf32SectionHeader *symbolTable;
  Elf32SectionHeader *stringTable;
  Elf32SectionHeader *gotTable; // Global offset table.
  Elf32SectionHeader *relTable;
  Elf32SectionHeader *sectionHeaders;
public:
  char               *filename;
};

#endif
